package cn.itcast.mq.config;



import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @Author: ahcfl
 * @Date: 2021年07月20日 22:21
 * @Description:
 * **死信交换机**（Dead Letter Exchange，检查DLX）
 * 当一个队列中的消息满足下列情况之一时，可以成为死信（dead letter）：
 * - 消费者使用basic.reject或 basic.nack声明消费失败，并且消息的requeue参数设置为false
 * - 消息是一个过期消息，超时无人消费
 * - 要投递的队列消息满了，无法投递
 *在失败重试策略中，默认的RejectAndDontRequeueRecoverer会在本地重试次数耗尽后，
 * 发送reject给RabbitMQ，消息变成死信，被丢弃。
 * 我们可以给simple.queue添加一个死信交换机，给死信交换机绑定一个队列。
 * 这样消息变成死信后也不会丢弃，而是最终投递到死信交换机，路由到与死信交换机绑定的队列。
 */
@Configuration
public class DlMsgConfig {

    @Bean
    public DirectExchange simpleDirectExchange(){
        return new DirectExchange("simple.direct");
    }

    // 声明普通的 simple.queue队列，并且为其 ==》 指定死信交换机：dl.direct
    /*
    *  ERROR 43896 --- [68.136.128:5672] o.s.a.r.c.CachingConnectionFactory
    *  : Channel shutdown: channel error; protocol method: #method<channel.close>(reply-code=406,
    * reply-text=PRECONDITION_FAILED - inequivalent arg 'x-dead-letter-exchange' for queue
    * 'simple.queue' in vhost '/': received the value 'dl.direct' of
    * type 'longstr' but current is none, class-id=50, method-id=10)
    *
    * // 之前声明一次 再次声明 信息不匹配 simple.queue删除之
    * */
    @Bean
    public Queue simpleQueue(){
        return QueueBuilder
                .durable("simple.queue")
                .deadLetterExchange("dl.direct") // 死信交换机
                .deadLetterRoutingKey("dl") // 死信交换机的RoutingKey
                .build();
    }

    // simple.queue 绑定到 交换机simple.direct  指定routingKey="simple"
    @Bean
    public Binding simpleBinding() {
        return BindingBuilder.bind(simpleQueue())
                .to(simpleDirectExchange()).with("simple");
    }

    // 声明死信交换机 dl.direct
    @Bean
    public DirectExchange dlDirectExchange(){
        return new DirectExchange("dl.direct");
    }
    // 声明存储死信的队列 dl.queue  默认持久化
    @Bean
    public Queue dlQueue(){
        return QueueBuilder.durable("dl.queue").build();
    }

    // 将死信队列 与 死信交换机绑定 (指定simple.queue相同的routingKey)
    // 消息通过交换机投放到 dl.queue中
    @Bean
    public Binding dlBinding(){
        return BindingBuilder.bind(dlQueue())
                .to(dlDirectExchange())
                .with("dl");
    }

}
